From ff6b84ff8818ee96f1d6cf479f72b2127eddec43 Mon Sep 17 00:00:00 2001 From: Brandon Eng Date: Wed, 17 Jan 2024 21:42:00 +0700 Subject: Group expenses (#48) * Group expenses my date * Group expenses my date * typescript errors * prettier * getExpenseGroup * update logic to use dayjs * clean up --- src/app/groups/[groupId]/expenses/expense-list.tsx | 177 ++++++++++++++------- 1 file changed, 117 insertions(+), 60 deletions(-) (limited to 'src/app/groups/[groupId]/expenses/expense-list.tsx') diff --git a/src/app/groups/[groupId]/expenses/expense-list.tsx b/src/app/groups/[groupId]/expenses/expense-list.tsx index 9217123..1a36179 100644 --- a/src/app/groups/[groupId]/expenses/expense-list.tsx +++ b/src/app/groups/[groupId]/expenses/expense-list.tsx @@ -3,7 +3,8 @@ import { CategoryIcon } from '@/app/groups/[groupId]/expenses/category-icon' import { Button } from '@/components/ui/button' import { getGroupExpenses } from '@/lib/api' import { cn } from '@/lib/utils' -import { Participant } from '@prisma/client' +import { Expense, Participant } from '@prisma/client' +import dayjs, { type Dayjs } from 'dayjs' import { ChevronRight } from 'lucide-react' import Link from 'next/link' import { useRouter } from 'next/navigation' @@ -16,6 +17,46 @@ type Props = { groupId: string } +const EXPENSE_GROUPS = { + THIS_WEEK: 'This week', + EARLIER_THIS_MONTH: 'Earlier this month', + LAST_MONTH: 'Last month', + EARLIER_THIS_YEAR: 'Earlier this year', + LAST_YEAR: 'Last year', + OLDER: 'Older', +} + +function getExpenseGroup(date: Dayjs, today: Dayjs) { + if (today.isSame(date, 'week')) { + return EXPENSE_GROUPS.THIS_WEEK + } else if (today.isSame(date, 'month')) { + return EXPENSE_GROUPS.EARLIER_THIS_MONTH + } else if (today.subtract(1, 'month').isSame(date, 'month')) { + return EXPENSE_GROUPS.LAST_MONTH + } else if (today.isSame(date, 'year')) { + return EXPENSE_GROUPS.EARLIER_THIS_YEAR + } else if (today.subtract(1, 'year').isSame(date, 'year')) { + return EXPENSE_GROUPS.LAST_YEAR + } else { + return EXPENSE_GROUPS.OLDER + } +} + +function getGroupedExpensesByDate( + expenses: Awaited>, +) { + const today = dayjs() + return expenses.reduce( + (result: { [key: string]: Expense[] }, expense: Expense) => { + const expenseGroup = getExpenseGroup(dayjs(expense.expenseDate), today) + result[expenseGroup] = result[expenseGroup] ?? [] + result[expenseGroup].push(expense) + return result + }, + {}, + ) +} + export function ExpenseList({ expenses, currency, @@ -44,67 +85,83 @@ export function ExpenseList({ const getParticipant = (id: string) => participants.find((p) => p.id === id) const router = useRouter() + const groupedExpensesByDate = getGroupedExpensesByDate(expenses) + return expenses.length > 0 ? ( - expenses.map((expense) => ( -
{ - router.push(`/groups/${groupId}/expenses/${expense.id}/edit`) - }} - > - -
-
- {expense.title} -
-
- Paid by {getParticipant(expense.paidById)?.name}{' '} - for{' '} - {expense.paidFor.map((paidFor, index) => ( - - {index !== 0 && <>, } - - { - participants.find((p) => p.id === paidFor.participantId) - ?.name - } - - - ))} -
-
-
-
- {currency} {(expense.amount / 100).toFixed(2)} -
-
- {formatDate(expense.expenseDate)} + Object.values(EXPENSE_GROUPS).map((expenseGroup: string) => { + const groupExpenses = groupedExpensesByDate[expenseGroup] + if (!groupExpenses) return null + return ( + +
+ {expenseGroup}
-
- -
- )) + {groupExpenses.map((expense: any) => ( +
{ + router.push(`/groups/${groupId}/expenses/${expense.id}/edit`) + }} + > + +
+
+ {expense.title} +
+
+ Paid by{' '} + {getParticipant(expense.paidById)?.name} for{' '} + {expense.paidFor.map((paidFor: any, index: number) => ( + + {index !== 0 && <>, } + + { + participants.find( + (p) => p.id === paidFor.participantId, + )?.name + } + + + ))} +
+
+
+
+ {currency} {(expense.amount / 100).toFixed(2)} +
+
+ {formatDate(expense.expenseDate)} +
+
+ +
+ ))} + + ) + }) ) : (

Your group doesn’t contain any expense yet.{' '} -- cgit v1.3